package com.zt.chatgpt.infrastructure.util.sdk;

import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author: zt
 * @Description: 解析微信xml消息
 * @create: 2024-05-12 22:27
 */

@Slf4j
public class XmlUtil {

    /**
     * 将XML格式的数据转换为Map形式。
     *
     * @param request HttpServletRequest对象，用于获取客户端上传的XML数据的输入流。
     * @return Map<String, String> 包含XML数据中所有元素名称和文本内容的映射。
     * @throws IOException 当读取输入流或释放资源时发生I/O错误。
     */
    public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {

        // 从request中获取输入流
        try (InputStream inputStream = request.getInputStream()){
            // 结果存放在map中
            Map<String, String> resultMap = new HashMap<>();
            // 读取输入流
            SAXReader reader = new SAXReader();
            // 读取xml文档
            Document document = reader.read(inputStream);
            // 获取xml根文件
            Element root = document.getRootElement();
            // 得到根节点下的所有叶子节点数据
            List<Element> elements = root.elements();
            // 遍历节点数据并填入map中
            for (Element e : elements) {
                resultMap.put(e.getName(), e.getText());
            }
            // 释放资源
            inputStream.close();
            return resultMap;
        }
    }

    /**
     * 将给定的map转换成XML格式的字符串，用于响应微信服务器请求。
     *
     * @param map 包含要转换成XML格式的数据的键值对。
     * @return 生成的XML字符串。如果在生成过程中发生异常，则返回null。
     */
    static String mapToXML(Map map) {
        StringBuffer sb = new StringBuffer();
        // 初始化XML字符串开头
        sb.append("<xml>");
        // 调用递归方法完成map到XML字符串的转换
        mapToXML2(map, sb);
        // 结束XML字符串
        sb.append("</xml>");
        try {
            return sb.toString();
        } catch (Exception e) {
            // 在转换过程中遇到异常时返回null
            return null;
        }
    }

    /**
     * 将Map对象转换为XML格式的字符串。
     * @param map 需要转换的Map对象，其中键值对代表XML的标签和内容。
     * @param sb 用于累积转换结果的StringBuffer对象。
     */
    private static void mapToXML2(Map map, StringBuffer sb) {
        // 获取map的所有键
        Set set = map.keySet();
        for (Object o : set) {
            String key = (String) o;
            Object value = map.get(key);
            // 如果值为null，则将其置为空字符串
            if (null == value) {
                value = "";
            }
            // 检查值是否为ArrayList类型
            if (value.getClass().getName().equals("java.util.ArrayList")) {
                ArrayList list = (ArrayList) map.get(key);
                // 开始标签
                sb.append("<").append(key).append(">");
                // 遍历ArrayList，将每个HashMap转换为XML格式
                for (Object o1 : list) {
                    HashMap hm = (HashMap) o1;
                    mapToXML2(hm, sb);
                }
                // 结束标签
                sb.append("</").append(key).append(">");

            } else {
                // 检查值是否为HashMap类型
                if (value instanceof HashMap) {
                    // 对HashMap类型值进行递归转换
                    sb.append("<").append(key).append(">");
                    mapToXML2((HashMap) value, sb);
                    sb.append("</").append(key).append(">");
                } else {
                    // 处理非ArrayList和HashMap类型的值，将其作为CDATA段落添加到XML中
                    sb.append("<").append(key).append("><![CDATA[").append(value).append("]]></").append(key).append(">");
                }

            }

        }
    }

}
